---
title: How to decrypt and verify JWT token of auth.js
description: How to decrypt and verify JWT token of auth.js
image: /images/blog/blog-post-3.jpg
date: '2024-09-04'
---

[MemFree](https://www.memfree.me/) needs to support building vectorized indexes for local files.
Initially, I directly uploaded the files to a NextJS service deployed on Vercel.
After parsing the files and processing them into a unified format, I sent the text to the backend vector indexing service.

## 1 Vercel 413 FUNCTION_PAYLOAD_TOO_LARGE Error

I initially got the entire process running smoothly, and the tests were successful.
However, when I uploaded large files, I encountered the Vercel 413 `FUNCTION_PAYLOAD_TOO_LARGE` error.
After searching [MemFree](https://www.memfree.me/), I learned that this is a limitation of Vercel itself:

[How do I bypass the 4.5MB body size limit of Vercel Serverless Functions](https://vercel.com/guides/how-to-bypass-vercel-body-size-limit-serverless-functions)

Therefore, I decided to send the files directly from the browser to the backend vectorized indexing service. An important issue here is how to authenticate the vectorized indexing service without exposing the key.

After asking on [MemFree](https://www.memfree.me/), I was advised to let the backend Vector service and NextJS's auth.js share a key, and then directly parse and verify the token in the Vector service.

## 2 How to get auth token in auth.js

I have enabled JWT authentication in auth.js, so the authentication token can be obtained on the server side.

```ts
'use server';

import { cookies } from 'next/headers';

export const getAuthToken = async () => {
    const token =
        cookies().get('__Secure-authjs.session-token')?.value ??
        cookies().get('authjs.session-token')?.value;
    return {
        data: token,
    };
};
```

Once we get the token from the NextJS server, we can include the token in the header when sending requests to the backend vector service. A key issue that follows is how the backend vector service can verify the token generated by Next auth.js.

## 3 jsonwebtoken doesn't work

[MemFree](https://www.memfree.me/) suggested using the jsonwebtoken library for verification, but it didn't work.
However, [MemFree](https://www.memfree.me/) reminded me that the **token verification configuration and algorithm must be consistent with those in auth.js**.
So, I checked the source code of auth.js and found that it uses the jose library and the HKDF algorithm to generate the encryption key.

## 4 How to valid the auth.js token

### 4.1 Generate the same encryption key

```ts
async function getDerivedEncryptionKey(
    enc: string,
    keyMaterial: Parameters<typeof hkdf>[1],
    salt: Parameters<typeof hkdf>[2],
) {
    const length = enc === 'A256CBC-HS512' ? 64 : 32;
    return await hkdf(
        'sha256',
        keyMaterial,
        salt,
        `Auth.js Generated Encryption Key (${salt})`,
        length,
    );
}
```

It is important to note that the parameters for the hkdf method must be exactly the same as [the way encryption is generated according to the key in auth.js](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts#L187):

-   The first parameter, `enc` is the encryption algorithm.
-   The second parameter is the `AUTH_SECRET` key configured in the env file of the NextJS project.
-   The third parameter is the encryption salt. If it is a production environment using HTTPS encryption, the value is `__Secure-authjs.session-token`. If it is a local development environment, the value is `authjs.session-token`.

## 4.2 Decrypt or Verify Token

```ts
async function decryptToken(token: string, isDev: boolean) {
    const salt = isDev
        ? 'authjs.session-token'
        : `__Secure-authjs.session-token`;
    const encryptionKey = await getDerivedEncryptionKey(enc, JWT_SECRET, salt);
    const { payload } = await jwtDecrypt(token, encryptionKey, {
        clockTolerance: 15,
        keyManagementAlgorithms: [alg],
        contentEncryptionAlgorithms: [enc, 'A256GCM'],
    });
    return payload;
}
```

The core is to call `jwtDecrypt` method of jose. The third parameter of jwtDecrypt needs to be exactly the same as [auth.js](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts#L75)

This is the complete code of MemFree backend vector service: [vector auth code](https://github.com/memfreeme/memfree/blob/main/vector/auth.ts)
